using StackExchange.Redis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Lzfy_Refund_Service.Services
{
    /// <summary>
    /// Redis服务实现类
    /// </summary>
    public class RedisService : IRedisService, IDisposable
    {
        private readonly IConnectionMultiplexer _redis;
        private readonly IDatabase _database;
        private readonly ILogger<RedisService> _logger;
        private readonly int _databaseNumber;

        public RedisService(IConfiguration configuration, ILogger<RedisService> logger)
        {
            _logger = logger;
            
            var connectionString = configuration.GetValue<string>("Redis:ConnectionString") 
                ?? throw new InvalidOperationException("Redis连接字符串未配置");
            
            _databaseNumber = configuration.GetValue<int>("Redis:Database", 1);
            
            try
            {
                _redis = ConnectionMultiplexer.Connect(connectionString);
                _database = _redis.GetDatabase(_databaseNumber);
                
                _logger.LogInformation("Redis连接成功，数据库: {Database}", _databaseNumber);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis连接失败，连接字符串: {ConnectionString}", connectionString);
                throw;
            }
        }

        /// <summary>
        /// 设置键值对，带过期时间
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="expiry">过期时间</param>
        /// <returns>是否设置成功</returns>
        public async Task<bool> SetAsync(string key, string value, TimeSpan? expiry = null)
        {
            try
            {
                var result = await _database.StringSetAsync(key, value, expiry);
                
                if (result)
                {
                    _logger.LogDebug("Redis设置成功，键: {Key}, 过期时间: {Expiry}", key, expiry);
                }
                else
                {
                    _logger.LogWarning("Redis设置失败，键: {Key}", key);
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis设置异常，键: {Key}", key);
                return false;
            }
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>值</returns>
        public async Task<string?> GetAsync(string key)
        {
            try
            {
                var value = await _database.StringGetAsync(key);
                
                if (value.HasValue)
                {
                    _logger.LogDebug("Redis获取成功，键: {Key}", key);
                    return value;
                }
                else
                {
                    _logger.LogDebug("Redis键不存在，键: {Key}", key);
                    return null;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis获取异常，键: {Key}", key);
                return null;
            }
        }

        /// <summary>
        /// 检查键是否存在
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>是否存在</returns>
        public async Task<bool> ExistsAsync(string key)
        {
            try
            {
                var exists = await _database.KeyExistsAsync(key);
                _logger.LogDebug("Redis键存在检查，键: {Key}, 存在: {Exists}", key, exists);
                return exists;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis键存在检查异常，键: {Key}", key);
                return false;
            }
        }

        /// <summary>
        /// 删除键
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>是否删除成功</returns>
        public async Task<bool> DeleteAsync(string key)
        {
            try
            {
                var result = await _database.KeyDeleteAsync(key);
                
                if (result)
                {
                    _logger.LogDebug("Redis删除成功，键: {Key}", key);
                }
                else
                {
                    _logger.LogDebug("Redis删除失败或键不存在，键: {Key}", key);
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis删除异常，键: {Key}", key);
                return false;
            }
        }

        /// <summary>
        /// 批量检查键是否存在
        /// </summary>
        /// <param name="keys">键列表</param>
        /// <returns>存在的键列表</returns>
        public async Task<List<string>> BatchExistsAsync(IEnumerable<string> keys)
        {
            var existingKeys = new List<string>();
            
            try
            {
                var keyArray = keys.ToArray();
                var redisKeys = keyArray.Select(k => (RedisKey)k).ToArray();
                
                var results = await _database.KeyExistsAsync(redisKeys);
                
                for (int i = 0; i < keyArray.Length; i++)
                {
                    if ((results & (1L << i)) != 0)
                    {
                        existingKeys.Add(keyArray[i]);
                    }
                }
                
                _logger.LogDebug("Redis批量检查完成，总数: {Total}, 存在: {Existing}", 
                    keyArray.Length, existingKeys.Count);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis批量检查异常");
            }
            
            return existingKeys;
        }

        /// <summary>
        /// 设置键值对到指定数据库，带过期时间
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="database">数据库编号</param>
        /// <param name="expiry">过期时间</param>
        /// <returns>是否设置成功</returns>
        public async Task<bool> SetAsync(string key, string value, int database, TimeSpan? expiry = null)
        {
            try
            {
                var db = _redis.GetDatabase(database);
                var result = await db.StringSetAsync(key, value, expiry);
                
                if (result)
                {
                    _logger.LogDebug("Redis设置成功，键: {Key}, 数据库: {Database}, 过期时间: {Expiry}", key, database, expiry);
                }
                else
                {
                    _logger.LogWarning("Redis设置失败，键: {Key}, 数据库: {Database}", key, database);
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis设置异常，键: {Key}, 数据库: {Database}", key, database);
                return false;
            }
        }

        /// <summary>
        /// 从指定数据库获取值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="database">数据库编号</param>
        /// <returns>值</returns>
        public async Task<string?> GetAsync(string key, int database)
        {
            try
            {
                var db = _redis.GetDatabase(database);
                var value = await db.StringGetAsync(key);
                
                if (value.HasValue)
                {
                    _logger.LogDebug("Redis获取成功，键: {Key}, 数据库: {Database}", key, database);
                    return value;
                }
                else
                {
                    _logger.LogDebug("Redis键不存在，键: {Key}, 数据库: {Database}", key, database);
                    return null;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis获取异常，键: {Key}, 数据库: {Database}", key, database);
                return null;
            }
        }

        /// <summary>
        /// 从指定数据库删除键
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="database">数据库编号</param>
        /// <returns>是否删除成功</returns>
        public async Task<bool> DeleteAsync(string key, int database)
        {
            try
            {
                var db = _redis.GetDatabase(database);
                var result = await db.KeyDeleteAsync(key);
                
                if (result)
                {
                    _logger.LogDebug("Redis删除成功，键: {Key}, 数据库: {Database}", key, database);
                }
                else
                {
                    _logger.LogDebug("Redis删除失败或键不存在，键: {Key}, 数据库: {Database}", key, database);
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis删除异常，键: {Key}, 数据库: {Database}", key, database);
                return false;
            }
        }

        /// <summary>
        /// 获取指定数据库中匹配模式的所有键
        /// </summary>
        /// <param name="pattern">匹配模式</param>
        /// <param name="database">数据库编号</param>
        /// <returns>匹配的键列表</returns>
        public async Task<List<string>> GetKeysAsync(string pattern, int database)
        {
            var keys = new List<string>();
            
            try
            {
                var server = _redis.GetServer(_redis.GetEndPoints().First());
                var db = _redis.GetDatabase(database);
                
                await foreach (var key in server.KeysAsync(database, pattern))
                {
                    if (!string.IsNullOrEmpty(key))
                    {
                        keys.Add(key!);
                    }
                }
                
                _logger.LogDebug("Redis获取键列表成功，模式: {Pattern}, 数据库: {Database}, 数量: {Count}", 
                    pattern, database, keys.Count);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis获取键列表异常，模式: {Pattern}, 数据库: {Database}", pattern, database);
            }
            
            return keys;
        }

        /// <summary>
        /// 批量检查指定数据库中键是否存在
        /// </summary>
        /// <param name="keys">键列表</param>
        /// <param name="database">数据库编号</param>
        /// <returns>存在的键列表</returns>
        public async Task<List<string>> BatchExistsAsync(IEnumerable<string> keys, int database)
        {
            var existingKeys = new List<string>();
            
            try
            {
                var db = _redis.GetDatabase(database);
                var keyArray = keys.ToArray();
                var redisKeys = keyArray.Select(k => (RedisKey)k).ToArray();
                
                var results = await db.KeyExistsAsync(redisKeys);
                
                for (int i = 0; i < keyArray.Length; i++)
                {
                    if ((results & (1L << i)) != 0)
                    {
                        existingKeys.Add(keyArray[i]);
                    }
                }
                
                _logger.LogDebug("Redis批量检查完成，数据库: {Database}, 总数: {Total}, 存在: {Existing}", 
                    database, keyArray.Length, existingKeys.Count);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Redis批量检查异常，数据库: {Database}", database);
            }
            
            return existingKeys;
        }

        public void Dispose()
        {
            _redis?.Dispose();
        }
    }
}